package com.cs.common.zip;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
public class Zip {
    private static int bufferSize = 1024*8;
    /**
     * 压缩文件
     */
    public static void zipFile (String sourceFileName, String zipFileName) throws IOException {
        //创建zip输出流
        FileOutputStream fileOutputStream = new FileOutputStream(zipFileName);
        ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);

        //调用函数
        zip(sourceFileName, zipOutputStream);

        zipOutputStream.close();
        fileOutputStream.close();
    }

    /**
     * 压缩文件列表
     */
    public static void zipFileList (List<String> sourceFileNameList, String zipFileName) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream(zipFileName);
        //创建zip输出流
        ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);

        for (String sourceFileName : sourceFileNameList) {
            //调用函数
            zip(sourceFileName, zipOutputStream);
        }
        zipOutputStream.closeEntry();
        zipOutputStream.close();
        fileOutputStream.close();
    }

    private static void zip(String sourceFileName, ZipOutputStream zipOutputStream) throws IOException {
        log.info("处理文件：{}", sourceFileName);
        File sourceFile = new File(sourceFileName);

        //不带路径的文件名
        String fileName = sourceFileName.substring(sourceFileName.lastIndexOf(File.separator) + 1);
        zipOutputStream.putNextEntry(new ZipEntry(fileName));

        FileInputStream fileInputStream = new FileInputStream(sourceFile);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

        int buff;
        while ( ( buff=bufferedInputStream.read()) != -1 ) {
            zipOutputStream.write(buff);
        }
        bufferedInputStream.close();
        fileInputStream.close();
    }

    /**
     * 压缩文件夹，注意zip文件不能在源文件夹之中
     */
    public static void zipFolder (String sourceFolderName, String zipFileName) throws IOException {
        //判断sourceFolder是否和zipFile在同一个目录中
        File zipFile = new File(zipFileName);
        if (zipFile.getPath().equals(sourceFolderName)) {
            throw new IOException("压缩文件夹" + sourceFolderName + "包含压缩文件" + zipFileName);
        }
        File sourceFolder = new File(sourceFolderName);
        if (!sourceFolder.isDirectory()) {
            throw new IOException(sourceFolderName + "必须为文件夹");
        }

        //创建zip输出流
        FileOutputStream fileOutputStream = new FileOutputStream(zipFileName);
        ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);

        File[] files = sourceFolder.listFiles();
        for (File file : files) {
            zipFolderProcess(file, zipOutputStream, "");
        }

        zipOutputStream.close();
        fileOutputStream.close();
    }

    private static void zipFolderProcess(File sourceFile, ZipOutputStream zipOutputStream, String base) throws IOException {
        log.info("处理：base={} file={}", base, sourceFile.getName());

        if(sourceFile.isDirectory()) {
            //创建目录
            log.info("创建目录：{}", base + sourceFile.getName() + "/");
            zipOutputStream.putNextEntry(new ZipEntry(base + sourceFile.getName() + "/"));
            //取出文件夹中的文件或目录
            File[] files = sourceFile.listFiles();
            for (File file : files) {
                log.info("递归调用 base={} file={}", base + sourceFile.getName() + "/", file.getName());
                zipFolderProcess(file, zipOutputStream, base + sourceFile.getName() + "/");
            }
        } else {
            zipOutputStream.putNextEntry(new ZipEntry(base + sourceFile.getName()));

            FileInputStream fileInputStream = new FileInputStream(sourceFile);
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

            int buff;
            while ( ( buff=bufferedInputStream.read()) != -1 ) {
                zipOutputStream.write(buff);
            }
            bufferedInputStream.close();
            fileInputStream.close();
        }
    }
}
